package base.shiro.demo.autho2;

import com.alibaba.fastjson.JSONObject;
import base.shiro.demo.ex.ServiceException;
import base.shiro.demo.util.Res;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.http.HttpStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 自定义过滤
 */
public class CustomOAuth2Filter extends AuthenticatingFilter {
    /**
     * 获取请求的token信息
     */
    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        String requestToken = getRequestToken((HttpServletRequest) request);
        if(StringUtils.isEmpty(requestToken)) {
            return null;
        }
        //解析获取token
//        return new UsernamePasswordToken(requestToken);
        return createToken("张删", "123456", request, response);
    }

    /**
     * 处理访问被拦截拒绝的请求
     * false是直接响应，true继续请求
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        String requestToken = getRequestToken((HttpServletRequest) request);
        if(StringUtils.isEmpty(requestToken) || "null".equals(requestToken)){
            return false;
        }
        //执行登录认证校验（这里会最终调用到我们自定义的CustomRealm#doGetAuthenticationInfo）
        //这里会执行的自定义CustomOAuth2Filter#createToken -> CustomRealm#supports -> CustomRealm#doGetAuthenticationInfo
        return executeLogin(request, response);
    }

    /**
     * 登录失败执行
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        try{
            HttpServletResponse httpServletResponse = (HttpServletResponse)response;
            httpServletResponse.setContentType("application/json;charset=utf-8");
            httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
            httpServletResponse.setHeader("Access-Control-Allow-Origin", getOrigin());
            //处理登录失败异常
            Throwable throwable = e.getCause() == null? e: e.getCause();
            Res r = new Res().error(HttpStatus.SERVICE_UNAVAILABLE.value(), throwable.getMessage());
            String json = JSONObject.toJSONString(r);
            httpServletResponse.getWriter().println(json);
        }catch (IOException e1) {
            throw new ServiceException(401, "登录认证失败！");
        }
        return false;
    }

    private String getOrigin(){
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        if(!ObjectUtils.isEmpty(servletRequestAttributes)){
            HttpServletRequest request = servletRequestAttributes.getRequest();
            return request.getHeader("Origin");
        }
        return null;
    }

    private String getRequestToken(HttpServletRequest request){
        String token = request.getHeader("token");
        if(StringUtils.isEmpty(token)){
            token = request.getParameter("token");
        }
        return token;
    }
}
